#include "Game.h"

Game::Game() {
	spawn_delay = 5000;
	spawn_next = time_paused = SDL_GetTicks();

	alive_buildings = BUILDINGS_COUNT;
	game_player_damage = 0;
}

Game::~Game() {

}

void Game::setup() {
	// Set our scene
	setBackground("images/Background.png");

	game_ground.setImage("images/Ground.png");
	game_ground.set_world_position(0, height - game_ground.get_height());
	game_ground.move();

	// Create our buildings
	for (int i = 0; i < BUILDINGS_COUNT; i++) {
		game_buildings[i].setImage("images/Building.png", 3);
		game_buildings[i].set_transparent_colour(255,255,255);

		float x = (i < (BUILDINGS_COUNT/2) ? 40.8 + (i * (40.8 + game_buildings[i].get_width())) : width - (((i - (BUILDINGS_COUNT/2) + 1) * (40.8 + game_buildings[i].get_width())))); // Make sure they're placed properly
		float y = height - (game_ground.get_height() + game_buildings[0].get_height());
		game_buildings[i].set_world_position(x, y);
		game_buildings[i].move();
	}

	// Create the player from it's parts
	game_player[0].setImage("images/Player_Base.png", 2);
	game_player[0].set_transparent_colour(255,255,255);
	game_player[0].set_auto_move(1);
	game_player[0].set_world_position((width/2) - (game_player[0].get_width()/2), height - (game_ground.get_height() + game_player[0].get_height()));
	game_player[0].move();

	game_player[1].setImage("images/Player_Gun.png", 2);
	game_player[1].set_transparent_colour(255,255,255);
	game_player[1].set_auto_animate(50);
	game_player[1].set_world_position(float(game_player[0].get_x() + (game_player[0].get_width()*0.5) - (game_player[1].get_width()*0.5)), float(game_player[0].get_y() - (game_player[1].get_height()*0.6)));
	// End create player

	// Create our bullets
	for (int i = 0; i < MAX_BULLETS; i++) {
		game_bullets[i].setImage("images/Bullet.png", 2);
		game_bullets[i].set_transparent_colour(255,255,255);
		game_bullets[i].set_auto_animate(75);
		game_bullets[i].set_auto_move(0);
		game_bullets[i].set_world_position_x(-100);
		
		game_bullets_can_fire.push_back(&game_bullets[i]); // Add them to our bullet list
	}

	// Create the health meter sprite
	game_health.setImage("images/Health.png", 7);
	game_health.set_transparent_colour(255,0,255);
	game_health.set_world_position(-50.0f, float(height - (game_health.get_height() + 15))); // Set it in the right place
	game_health.move();

	//Sounds
	addSound("sounds/pew.wav", "BULLET_SOUND"); // sound for bullets when fired
	addSound("sounds/explode.wav","BUILDING_HIT"); //sound for building being hit
	addSound("sounds/explode.wav","MISSILE_HIT"); //sound for missile being shot

	score = 0; //starting score 
}

AWSprite * Game::CreateMissile() {
	AWSprite *missile = new AWSprite;

	missile->setImage("images/Missile.png", 4);
	missile->set_transparent_colour(255,255,255);
	missile->set_auto_animate(100);

	missile->set_world_position(float(missile->get_width() + rnd.number(width-(missile->get_width()*2))),float(-missile->get_height()));
	missile->set_auto_move(1);

	missile->set_y_velocity(0.5 + (rnd.number()*0.5));

	return missile;
}

void Game::logic() {
	// Check if there's enough buildings left...
	if (alive_buildings < (BUILDINGS_COUNT/2)) {
		draw();
		gameover = true; // ...if not, gameover.
	}

	ThinkPlayer();
	ThinkBullets();
	ThinkMissiles();
}

void Game::draw() {
	game_ground.draw();
	
	for (int i = 0; i < BUILDINGS_COUNT; i++) {
		game_buildings[i].draw();
	}

	for (int i = 0; i < PLAYER_PEICES; i++) {
		game_player[i].draw();
	}

	for (int i = 0; i < MAX_BULLETS; i++) {
		game_bullets[i].draw();
	}

	/*	This just iterates through the list of missiles. I can't use a constant array here because we could theoretically have an infinite amount of missles.
		Obviously this would never happen but I'd like to make sure there is the compatibility for it. */
	for (list<AWSprite*>::iterator it = game_missiles.begin(); it != game_missiles.end(); it++) {
		(*it)->draw();
	}

	game_health.draw();

	int px = width - 120;
	int py = height - 40;
	px = print("Score: ", px, py, WHITE);
	print ( score, px, py, WHITE);

}

void Game::FireBullet() {
	// Check to see if we can fire a bullet
	if (game_bullets_can_fire.size() > 0) {
		AWSprite *bullet = game_bullets_can_fire.back(); // If we can, grab a bullet from the back of the list

		// Make it visible, and allow it to move
		(*bullet).set_visibility(true);
		(*bullet).set_auto_move(1);
		
		// Set its position to our gun and set its velocity
		(*bullet).set_world_position(float(game_player[1].get_x() + (game_player[1].get_width()*0.5) - ((*bullet).get_width()*0.5)), float(game_player[1].get_y() - ((*bullet).get_height()*0.6)));
		(*bullet).set_y_velocity(-4);
		
		// Remove this bullet from our list
		game_bullets_can_fire.pop_back();

		//play the bullet sound
		playSound("BULLET_SOUND"); 
	}
}

void Game::HitBuilding(int i) {
	int frame = game_buildings[i].get_currentFrame() + 1; // Show the next level of damage

	if (frame < game_buildings[i].get_frameCount()) {
		game_buildings[i].set_currentFrame(frame);
		DamagePlayer(0.25); // Damage the player too
	} else {
		game_buildings[i].set_visibility(false);
		alive_buildings--; // If we die, update the amount of live buildings
	}
	
	playSound("BUILDING_HIT");
}

void Game::DamagePlayer(float dmg) {
	if (dmg > 0) { // If we're taking health,
		score -= 50; // also damage our score!
	}

	if ((game_player_damage + dmg) < 0) {
		game_player_damage = 0;
	} else if ((game_player_damage + dmg) < PLAYER_MAXDAMAGE) {
		game_player_damage+= dmg;
	} else {
		game_player_damage = PLAYER_MAXDAMAGE;
	}

	game_health.set_currentFrame(int(game_player_damage/0.25)); // Update the health bar to show our health

	MovePlayer(); // Make sure we're moving properly
}

void Game::HealPlayer(float heal) {
	DamagePlayer(-heal);
}

void Game::MovePlayer() {
	Uint8 *keystate = SDL_GetKeyState(NULL);

	// Set the base's velocity based on the keys being pressed
	game_player[0].set_x_velocity(((keystate[SDLK_d] != 0|| keystate[SDLK_RIGHT] != 0)-(keystate[SDLK_a] != 0 || keystate[SDLK_LEFT] != 0))*(PLAYER_SPEEDMULT-game_player_damage));
}

void Game::ThinkPlayer() {
	// Update each of the piece of the player
	for (int i = 0; i < PLAYER_PEICES; i++) {
		if (!(game_player[i].get_x() + (game_player[i].get_width()*0.5) + game_player[i].get_x_velocity() < 0 || game_player[i].get_x() + (game_player[i].get_width()*0.5) + game_player[i].get_x_velocity() > width)) {
			game_player[i].update_everything();
		}
	}

	game_player[1].set_world_position(float(game_player[0].get_x() + (game_player[0].get_width()*0.5) - (game_player[1].get_width()*0.5)), float(game_player[0].get_y() - (game_player[1].get_height()*0.6)));
	game_player[1].move();

	if (game_player[0].get_x_velocity() != 0) {
		game_player[0].set_auto_animate(150);
	} else {
		game_player[0].set_auto_animate(0);
	}
}

void Game::ThinkBullets() {
	// Go through the bullets
	for (int i = 0; i < MAX_BULLETS; i++) {
		bool hit_missile = false;

		// Check with each missile to see if it's collided with it
		for (list<AWSprite*>::iterator it = game_missiles.begin(); it != game_missiles.end(); it++) {
			if (game_bullets[i].pp_collision(*it)) {
				game_missiles.remove(*it);
				hit_missile = true;
				HealPlayer(0.5); // Heal the player if it has
				score += 100;

				playSound("BUILDING_HIT");
				break;
			}
		}

		// If the bullet is no longer on screen or there is a collision
		if (game_bullets[i].get_y() + game_bullets[i].get_height() < 0 || hit_missile) {
			game_bullets[i].set_visibility(false);
			game_bullets[i].set_auto_move(0);
			game_bullets[i].set_world_position_x(-100);
			game_bullets[i].set_world_position_y(height);

			game_bullets_can_fire.push_back(&game_bullets[i]); // Add it back into our list so that we can fire it
		}

		game_bullets[i].update_everything(); // Update each bullet
	}
}

void Game::ThinkMissiles() {
	// Spawn missile if there has been enough time passed since the last spawn
	if (SDL_GetTicks() >= spawn_next) {
		spawn_next+= spawn_delay;

		if (spawn_delay < 1250) {
			spawn_delay = 1250;
		} else if (spawn_delay > 1250) {
			spawn_delay-= rnd.number(50,100);
		}

		AWSprite *missile = CreateMissile();
		game_missiles.push_back(missile); // Add it to our list
	}

	// This just iterates through the list of missiles
	for (list<AWSprite*>::iterator it = game_missiles.begin(); it != game_missiles.end(); it++) {
		if (game_ground.bb_collision(*it)) {

			bool building_hit = false;

			// Check with each building to whether it's close enough to take damage
			for (int i = 0; i < BUILDINGS_COUNT; i++) {
				float x1 = game_buildings[i].get_x() + (game_buildings[i].get_width()*0.5);
				float x2 = (*it)->get_x() + ((*it)->get_width()*0.5);
				float dist = abs(x1 - x2);

				if (dist < 40 && game_buildings[i].is_visible()) {
					HitBuilding(i);
					building_hit = true;
				}
			}
			
			// If the missile hasn't hit any buildings but has still collided with the ground, damage the player
			if (!building_hit) DamagePlayer(0.25);

			// Remove the missile from our list (AND EXISTENCE)
			game_missiles.remove(*it);
			break;
		}

		bool player_hit = false;

		// Check if a missile has collided with the player
		for (int i = 0; i < PLAYER_PEICES; i++) {
			if (game_player[i].pp_collision(*it)) {
				player_hit = true;
				game_missiles.remove(*it);
				DamagePlayer(0.25); // Damage the player if it has
				break;
			}
		}

		if (player_hit) break; // Break from the loop if it has

		bool building_hit = false;

		// Check each buildings 
		for (int i = 0; i < BUILDINGS_COUNT; i++) {
			if (game_buildings[i].pp_collision(*it)) {
				building_hit = true;
				game_missiles.remove(*it);
				HitBuilding(i);
				break;
			}
		}
		
		if (building_hit) break;

		(*it)->update_everything(); // Update the missile
	}
}

void Game::onKeyReleased() {
	switch (keyUp) {
		case SDLK_a:
		case SDLK_d:
		case SDLK_LEFT:
		case SDLK_RIGHT:
			MovePlayer();
			break;
		case SDLK_RETURN:
			if (paused || wait_for_user) {
				wait_for_user = false;
				paused = false;
				spawn_next+= SDL_GetTicks() - time_paused;
			} else if (gameover) {
				quit = true;
			}
			break;
		case SDLK_p:
			paused = true;
			time_paused = SDL_GetTicks();
			break;
	}
}

void Game::onKeyPressed() {
	switch (keyDown) {
		case SDLK_a:
		case SDLK_d:
		case SDLK_LEFT:
		case SDLK_RIGHT:
			MovePlayer();
			break;
		case SDLK_SPACE:
			FireBullet();
			break;
	}
}